package rexsee.multimedia;

import java.lang.reflect.Method;

import rexsee.core.browser.Browser;
import rexsee.core.utilities.RexseeClazz;
import android.hardware.Camera;
import android.view.KeyEvent;
import android.view.SurfaceHolder;

public class CameraPreviewDialog extends SurfaceDialog {

	public Camera camera = null;
	private OnCameraPreviewKeyDown mOnKeyDown = null;

	public CameraPreviewDialog(Browser browser, String style) {
		super(browser, style);
	}

	public void start(final int orientation, final Runnable startedRunnable, OnCameraPreviewKeyDown onKeyDown) {
		mOnKeyDown = onKeyDown;
		try {
			SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
				@Override
				public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
				}
				@Override
				public void surfaceCreated(SurfaceHolder holder) {
					try {
						camera = Camera.open();
						camera.setErrorCallback(new Camera.ErrorCallback() {
							@Override
							public void onError(int error, Camera camera) {
								String errorString;
								switch (error) {
									case Camera.CAMERA_ERROR_SERVER_DIED :
									errorString = "CAMERA_ERROR_SERVER_DIED";
									break;
								default :
									errorString = "CAMERA_ERROR_UNKNOWN";
									break;
							}
							mBrowser.exception(this.getClass().getName(), errorString);
						}
						});
						//camera.setDisplayOrientation(orientation);
						try {
							Method method = RexseeClazz.getMethod(Camera.class, "setDisplayOrientation");
							if (method != null) method.invoke(camera, new Object[]{orientation});
						} catch (Exception e) {
						}
						camera.setPreviewDisplay(holder);
						camera.startPreview();
						if (startedRunnable != null) startedRunnable.run();
					} catch (Exception e) {
						if (mBrowser != null) mBrowser.exception(this.getClass().getName(), e);
					}
				}
				@Override
				public void surfaceDestroyed(SurfaceHolder holder) {
					if (camera != null) {
						try {
							camera.stopPreview();
							camera.release();
						} catch (Exception e) {
						}
						camera = null;
					}
				}
			};
			super.start(callback);
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), e);
		}
	}

	@Override
	public final boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK
				|| keyCode == KeyEvent.KEYCODE_MENU
				|| keyCode == KeyEvent.KEYCODE_SEARCH
				|| keyCode == KeyEvent.KEYCODE_FOCUS) {
			if (mOnKeyDown != null) mOnKeyDown.run(keyCode);
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
			zoomOut();
			return true;
		} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
			zoomIn();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	public boolean zoom(int value) {
		if (camera == null) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera is not started.");
			return false;
		}
		Camera.Parameters paras = camera.getParameters();
		int maxZoom = getMaxZoom();
		if (value < 0 || value > maxZoom) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Zoom value should not exceed 0~" + maxZoom + ".");
			return false;
		}
		/* Not support 2.1-
		camera.setZoomChangeListener(new OnZoomChangeListener() {
			@Override
			public void onZoomChange(int zoomValue, boolean stopped, Camera camera) {
				if (stopped) mBrowser.eventList.run(EVENT_ONCAMERAZOOMFINISHED, new String[]{String.valueOf(zoomValue)});
			}
		});
		*/
		try {
			if (isSmoothZoomSupported()) {
				//camera.startSmoothZoom(value); 2.2+
				try {
					Method method = RexseeClazz.getMethod(Camera.class, "startSmoothZoom");
					if (method != null) method.invoke(camera, new Object[]{value});
					else {
						mBrowser.exception(this.getClass().getName(), "Can not find the method startSmoothZoom. ");
						return false;
					}
				} catch (Exception e) {
					mBrowser.exception(this.getClass().getName(), "Can not find the method. SmoothZoom: " + e.getLocalizedMessage());
					return false;
				}
				return true;
			} else if (isZoomSupported()) {
				//paras.setZoom(value);  2.2+
				//camera.setParameters(paras);
				try {
					Method method = RexseeClazz.getMethod(Camera.Parameters.class, "setZoom");
					if (method != null) method.invoke(paras, new Object[]{value});
					else {
						mBrowser.exception(this.getClass().getName(), "Can not find the method setZoom. ");
						return false;
					}
					camera.setParameters(paras);
				} catch (Exception e) {
					mBrowser.exception(this.getClass().getName(), "Can not find the method. Zoom: " + e.getLocalizedMessage());
					return false;
				}
				return true;
			} else {
				if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera does not support zoom function.");
				return false;
			}
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), e);
			return false;
		}
	}
	public boolean isSmoothZoomSupported() {
		if (camera == null) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera is not started.");
			return false;
		}
		Camera.Parameters paras = camera.getParameters();
		//return paras.isZoomSupported();
		try {
			Method method = Camera.Parameters.class.getMethod("isSmoothZoomSupported");
			return (Boolean) method.invoke(paras);
		} catch (Exception e) {
			mBrowser.exception(this.getClass().getName(), "Can not find the method isSmoothZoomSupported.");
			return false;
		}
	}
	public boolean isZoomSupported() {
		if (camera == null) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera is not started.");
			return false;
		}
		Camera.Parameters paras = camera.getParameters();
		//return paras.isZoomSupported();
		try {
			Method method = Camera.Parameters.class.getMethod("isZoomSupported");
			return (Boolean) method.invoke(paras);
		} catch (Exception e) {
			mBrowser.exception(this.getClass().getName(), "Can not find the method isZoomSupported.");
			return false;
		}
	}
	public int getMaxZoom() {
		if (camera == null) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera is not started.");
			return -1;
		}
		Camera.Parameters paras = camera.getParameters();
		//return (paras.isZoomSupported()) ? paras.getMaxZoom() : -1;
		try {
			Method method = Camera.Parameters.class.getMethod("isZoomSupported");
			boolean support = (Boolean) method.invoke(paras);
			if (!support) return -1;
			method = Camera.Parameters.class.getMethod("getMaxZoom");
			return (Integer) method.invoke(paras);
		} catch (Exception e) {
			mBrowser.exception(this.getClass().getName(), "Can not find the method..");
			return -1;
		}
	}
	public int getCurrentZoom() {
		if (camera == null) {
			if (mBrowser != null) mBrowser.exception(this.getClass().getName(), "Camera is not started.");
			return -1;
		}
		Camera.Parameters paras = camera.getParameters();
		try {
			Method method = Camera.Parameters.class.getMethod("isZoomSupported");
			boolean support = (Boolean) method.invoke(paras);
			if (!support) return -1;
			method = Camera.Parameters.class.getMethod("getZoom");
			return (Integer) method.invoke(paras);
		} catch (Exception e) {
			mBrowser.exception(this.getClass().getName(), "Can not find the method..");
			return -1;
		}
	}

	public boolean zoomIn() {
		int max = getMaxZoom();
		int curr = getCurrentZoom();
		if (max > 0 && curr >= 0 && max > curr) {
			curr = curr + 1;
			return zoom(curr);
		} else {
			return false;
		}
	}
	public boolean zoomOut() {
		int curr = getCurrentZoom();
		if (curr > 0) {
			curr = curr - 1;
			return zoom(curr);
		} else {
			return false;
		}
	}

	public static abstract class OnCameraPreviewKeyDown {
		public abstract void run(int keyCode);
	}

}
